package team2.game.crow;

import java.util.ArrayList;
import java.util.List;

import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.util.Debug;

import com.badlogic.gdx.math.Vector2;

public class Ship extends AnimatedSprite {
	
	// ===========================================================
    // Constants
    // ===========================================================
	
	// ===========================================================
    // Fields
    // ===========================================================
	public AnimatedSprite superLaser;
	public ArrayList<Laser> munnins;
	public SpritePool mPool;
	
	private float noControl;
	private float rateOfFire;
	private float superLaserDuration;
	private int lives;
	private int health;
	private float invuln;
	private boolean laser;
	private boolean superMode;
	private float superModeDuration;
	//private int superLaserTime;//May never be used....
	private Vector2 target;
	private float middle;
	private SpritePool lPool;
	private List<Laser> shots;
	private int laserLevel;//0: Double shot, 1:Double Shot w/2 angled shots, 2:Double Helix w/ diagonals, 3: GIant Laser
	private int shipLevel;//Max 12
	private int time;
	private AnimatedSprite booster1;
	private AnimatedSprite booster2;
	private AnimatedSprite laserShooter;
	private AnimatedSprite munnin;
	private float speed;
	private Vector2 dir;
	private HealthBar healthbar;
	private CrowActivity main;
	
	// ===========================================================
    // Constructors
    // ===========================================================

	Ship(float x, float y,final TiledTextureRegion cockpit,
			final TiledTextureRegion booster,
			final TiledTextureRegion munnin,
			final TiledTextureRegion laserShooter,
			final TiledTextureRegion superLaser,
			final TextureRegion laser,
			final TextureRegion afterImage,
			final List<Laser> shots,
			final SpritePool lPool,
			final CrowActivity main) {
		super(x, y, cockpit);
		this.munnin = new AnimatedSprite(x-30, y-13, munnin);
		this.laserShooter = new AnimatedSprite(x-7, y-21, laserShooter);
		this.booster1 = new AnimatedSprite(x-25, y+44, booster);
		this.booster2 = new AnimatedSprite(x+25, y+44, booster);
		this.superLaser = new AnimatedSprite(-280,0,superLaser);
		this.laser = true;
		this.lPool = lPool;
		this.mPool = new SpritePool(afterImage);
		this.munnins = new ArrayList<Laser>();
		this.middle = this.laserShooter.getBaseWidth()/2;
		this.target = new Vector2();
		this.laserLevel = 0;
		this.time = 0;
		this.shots = shots;
		this.dir = new Vector2();
		this.shipLevel = 0;
		this.speed = 40;
		this.superMode = false;
		this.lives = 3;
		this.health = 200;
		this.invuln = 0;
		this.rateOfFire = 0.5f;
		this.superModeDuration = 0;
		this.main = main;
	}
	
    // ===========================================================
    // Getter & Setter
    // ===========================================================
	
	public void setTarget(float x, float y){
		this.target.x = x;
		this.target.y = y;
	}
	
	public boolean hasLaser(){
		return this.laser;
	}
	
	public void setLaser(boolean bool){
		this.laser = bool;
	}
	
	public int getLaserLevel(){
		return laserLevel;
	}
	
	public int getHealth(){
		return health;
	}
	
	public boolean hasControl(){
		if(noControl > 0)
			return false;
		else
			return true;
	}
	
	public boolean isInvulnerable(){
		if(invuln > 0)
			return true;
		else
			return false;
	}
	
	public void setHealthBar(final HealthBar bar){
		this.healthbar = bar;
	}
	
	public int getLives(){
		return lives;
	}
	
    // ===========================================================
    // Methods for/from SuperClass/Interfaces
    // ===========================================================
	
	@Override
	protected void onManagedUpdate(float pSecondsElapsed){
		this.move(pSecondsElapsed);
		if(laser)
			this.fireLasers(pSecondsElapsed);
		this.incTime(pSecondsElapsed);
		super.onManagedUpdate(pSecondsElapsed);
	}
	
	// ===========================================================
    // Methods
    // ===========================================================
	
	public void move(float delta){
		//double angle;
		if(shipLevel < 12 | !superMode){
			if(!(Math.abs(target.x - this.mX) < speed) | !(Math.abs(target.y - this.mY) < speed)){
				float x = (this.mX);
				float y = (this.mY);
				dir.x = (x-target.x);
				dir.y = (y-target.y);
				dir.nor();
				//angle = Math.atan(dir.y/dir.x);
				//dir.x = (float)Math.cos(angle);
				//dir.y = (float)Math.sin(angle);
				dir.mul(-1);
				//Debug.d("X ="+dir.x+" Y="+dir.y);
				this.setPosition(x+(speed*dir.x),y+(speed*dir.y));
				this.munnin.setPosition(this.mX-30, this.mY-13);
				this.booster1.setPosition(this.mX-25, this.mY+44);
				this.booster2.setPosition(this.mX+25, this.mY+44);
				this.laserShooter.setPosition(this.mX-7, this.mY-21);
			}
			else {
				this.setPosition(target.x,target.y);
				this.munnin.setPosition(this.mX-30, this.mY-13);
				this.booster1.setPosition(this.mX-25, this.mY+44);
				this.booster2.setPosition(this.mX+25, this.mY+44);
				this.laserShooter.setPosition(this.mX-7, this.mY-21);
			}
			
		}
		else{
			float x = (this.mX-this.middle);
			float y = (this.mY-this.getHeight()/2);
			dir.x = (x-target.x);
			dir.y = (y-target.y);
			int extraShots = (int) (dir.len()/(speed));
			dir.nor();
			dir.mul(-1);
			for(int i = 0; i < extraShots; i++){
				Laser munnin = mPool.obtainPoolItem();
				munnin.setPosition(x+speed*(i*dir.x), y+speed*(i*dir.y));
				munnin.setAngle(0);
				munnin.setMode(0);
				munnin.setMid(this.mX+middle);
				munnins.add(munnin);
				if(munnin.getParent() == null){
					this.getParent().attachChild(munnin);
				}
			}
			this.setPosition(target.x-this.getWidth()/2, target.y-this.getHeight()/2);
			this.munnin.setPosition(this.mX-30, this.mY-13);
			this.booster1.setPosition(this.mX-25, this.mY+44);
			this.booster2.setPosition(this.mX+25, this.mY+44);
			this.laserShooter.setPosition(this.mX-7, this.mY-21);
			
		}
	}
	
	/**
	 * Fires the lasers based on the ships laser level
	 */
	public void fireLasers( float delta){
		rateOfFire -= delta;
		if(rateOfFire < 0){
			rateOfFire = 0.15f;
			switch(laserLevel){
			case 0:
				level0();
				break;
			case 1:
				level1();
				break;
			case 2:
				level2();
				break;
			case 3:
				if(superLaserDuration > 0){
					level3();
				}
				else{
					laserLevel--;
					this.superLaser.setPosition(-280,0);
				}					
				break;
			}
		}
		
	}
	
	/**
	 * An internal ship timer.
	 */
	public void incTime(float delta){
		time += 1;
		time = time%Integer.MAX_VALUE;
		
		if(time % 100 == 0){
			this.shipLevelUp();
		}
		
		if(noControl > 0){
			noControl -= delta;
		}
		
		if(invuln > 0){
			invuln -= delta;
			if(time%2 == 0)
				munnin.stopAnimation(15);
			else
				munnin.stopAnimation(shipLevel);
		}
		else{
			munnin.stopAnimation(shipLevel);
		}
		
		
		if(superMode){
			superModeDuration += delta;
			if(superModeDuration > 10){
				superMode = false;
				superModeDuration = 0;
				resetShip();
			}	
		}
		
		if(main.currentBoss != null)
		if(main.currentBoss.isEntering){
			laser = false;
			superLaser.setPosition(-280,0);
		}
		else
			laser = true;
		
		if(superLaserDuration > 0){
			superLaserDuration -= delta;
		}
			
	}
	
	/**
	 * Levels up the ships lasers.
	 */
	private void levelUp(){
		if(laserLevel < 3){
			laserLevel++;
			if(laserLevel == 3){
				superLaserDuration += 10;
				this.superLaser.animate(new long[]{100,100,100},0,2,true);
			}
		}
	}
	
	/**
	 * Levels up ship. Increments the wing animation to show the progress.
	 */
	private void shipLevelUp(){
		if(shipLevel < 12){
			shipLevel++;
			this.munnin.stopAnimation(shipLevel);
		}
	}
	
	/**
	 * LEts the ship go into super mode if it is able.
	 */
	public void goSuper(){
		if(shipLevel == 12){
			if(!superMode){
			this.animate(new long[] {100,100,100,100,100,100,100,100,100,100,100,100}, 0, 11, true);
			this.booster1.animate(new long[] {80, 80, 80, 80}, 4, 7, true);
	        this.booster2.animate(new long[] {80, 80, 80, 80}, 4, 7, true);
	        this.laserShooter.animate(new long[] {80, 80, 80, 80, 80, 80, 80, 80, 80, 80}, 10, 19, true);
			superMode = true;
			}
		}
	}
	
	/**
	 * 
	 * @param pUp The power up to be used
	 */
	public void usePowerUp(PowerUp pUp){
		CrowEnum type = pUp.getType();
		switch(type){
		case ONEUP:
			this.lives++;
			main.livesText.setText("Lives: "+lives);
			break;
		case LASERUP:
			levelUp();
			break;
		}
	}
	
	/**
	 * The ship takes damage and dies if its health reaches 0
	 * @param damage
	 * @return True if the if the game is over false if it isn't.
	 */
	public boolean takeDamage(int damage){
		this.health -= damage;
		this.healthbar.takeDamage(damage);
		invuln = 2;
		if(this.health <= 0){
			this.healthbar.healDamage(200);
			return this.die();
		}
		return false;
	}
	
	/**
	 * 
	 * @return True if it is game over false if it is not
	 */
	private boolean die(){
		lives--;
		main.livesText.setText("Lives: "+lives);
		if(lives < 0){
			AnimatedSprite explosion = new AnimatedSprite(this.getX()-20,this.getY()-20,main.shipExplosion);
			explosion.animate(200, false);
			this.getParent().attachChild(explosion);
			return true;
		}
		else{
			respawn();
			return false;
		}
	}
	
	public void level0(){
		int y = (time % 16);
		y *= (Math.PI/8);
		Laser shot = null;
		shot = lPool.obtainPoolItem();
		shot.setPosition(laserShooter.getX()+middle-25-(shot.getWidth()/2), laserShooter.getY()+y);
		shot.setAngle(0);
		shot.setMode(0);
		shot.setMid(this.mX+middle);
		shots.add(shot);
		if(shot.getParent() == null){
			this.getParent().attachChild(shot);
		}
		shot = lPool.obtainPoolItem();
		shot.setPosition(laserShooter.getX()+middle+25-(shot.getWidth()/2), laserShooter.getY()+y);
		shot.setAngle(0);
		shot.setMode(0);
		shot.setMid(this.mX+middle);
		shots.add(shot);
		if(shot.getParent() == null){
			this.getParent().attachChild(shot);
		}


	}
	
	public void level1(){
		int y = (time % 16);
		y *= (Math.PI/8);
		Laser shot = null;
		level0();
		shot = lPool.obtainPoolItem();
		shot.setPosition(laserShooter.getX()+middle-(shot.getWidth()/2)+y, laserShooter.getY()+y);
		shot.setMode(0);
		shot.setAngle(-Math.PI/3);
		shots.add(shot);
		if(shot.getParent() == null){
			this.getParent().attachChild(shot);
		}
		shot = lPool.obtainPoolItem();
		shot.setPosition(laserShooter.getX()+middle-(shot.getWidth()/2)-y, laserShooter.getY()+y);
		shot.setMode(0); 
		shot.setAngle(Math.PI/3);
		shots.add(shot);
		if(shot.getParent() == null){
			this.getParent().attachChild(shot);
		}

	}
	
	public void level2(){
		int y = (time % 16);
		y *= (Math.PI/8);
		double x;
		Laser shot = null;
		shot = lPool.obtainPoolItem();
		level1();
		x = 25*Math.sin(y);
		shot.setPosition((float)x+laserShooter.getX()+middle-(shot.getWidth()/2), laserShooter.getY());
		shot.setAngle(0);
		shot.setMode(0);
		shot.setMid(this.mX+middle);
		shots.add(shot);
		if(shot.getParent() == null){
			this.getParent().attachChild(shot);
		}
		shot = lPool.obtainPoolItem();
		x = -25*Math.sin(y);
		shot.setPosition((float)x+laserShooter.getX()+middle-(shot.getWidth()/2), laserShooter.getY());
		shot.setAngle(0);
		shot.setMode(0);
		shot.setMid(this.mX+middle);
		shots.add(shot);
		if(shot.getParent() == null){
			this.getParent().attachChild(shot);
		}
		shot = lPool.obtainPoolItem();
		shot.setPosition(laserShooter.getX()+middle+15-(shot.getWidth()/2), laserShooter.getY()+y);
		shot.setMode(0); 
		shot.setAngle(-Math.PI/6);
		shots.add(shot);
		if(shot.getParent() == null){
			this.getParent().attachChild(shot);
		}
		shot = lPool.obtainPoolItem();
		shot.setPosition(laserShooter.getX()+middle+15-(shot.getWidth()/2), laserShooter.getY()+y);
		shot.setMode(0); 
		shot.setAngle(Math.PI/6);
		shots.add(shot);
		if(shot.getParent() == null){
			this.getParent().attachChild(shot);
		}
			
	}
	
	public void level3(){
		if(laser){
			this.superLaser.setPosition(laserShooter.getX()+middle-(this.superLaser.getWidth()/2), laserShooter.getY()-this.superLaser.getHeight());
		}
		else{
			this.superLaser.setPosition(-280,0);
		}
	}
	
	/**
	 *  Initializes the ship with all of its pieces.
	 */
	public void initialize(){
		this.getParent().attachChild(this.munnin);
		this.getParent().attachChild(this.booster1);
		this.getParent().attachChild(this.booster2);
		this.getParent().attachChild(this.laserShooter);
		this.getParent().attachChild(this.superLaser);
		this.booster1.animate(new long[] {80, 80, 80, 80}, 0, 3, true);
        this.booster2.animate(new long[] {80, 80, 80, 80}, 0, 3, true);
		this.laserShooter.animate(new long[] {80, 80, 80, 80, 80, 80, 80, 80, 80, 80}, 0, 9, true);
		this.munnin.stopAnimation();
		this.stopAnimation(12);
		this.superLaser.stopAnimation();
		this.setTarget(240, 600);
		Debug.d(this.getParent().toString());
	}
	
	/**
	 * Resets the ship after super mode wares off.
	 */
	public void resetShip(){
		this.booster1.animate(new long[] {80, 80, 80, 80}, 0, 3, true);
        this.booster2.animate(new long[] {80, 80, 80, 80}, 0, 3, true);
		this.laserShooter.animate(new long[] {80, 80, 80, 80, 80, 80, 80, 80, 80, 80}, 0, 9, true);
		this.shipLevel = 0;
		this.munnin.stopAnimation(shipLevel);
		this.stopAnimation(12);
	}
	
	/**
	 * Used to respawn the ship after it is destroyed
	 */
	public void respawn(){
		this.resetShip();
		//this.healthbar.reset();
		this.health = 200;
		this.invuln = 5;
		this.noControl = 3;
		this.laserLevel = 0;
		this.superMode = false;
		this.setTarget(240, 600);
		this.move(0);
		this.superLaser.setPosition(-280,0);
		this.superLaser.stopAnimation();
	}
	
	/**
	 * Moves the ship to the top of the screen slowly
	 */
	public void dramaticMovement(float x, float y){
		this.setLaser(false);
		this.superLaser.setPosition(-280,0);
		this.setTarget(x, y);
		this.speed = 20;
		this.noControl = 10;
	}
	
	/**
	 * End the dramatic effects
	 */
	public void endDrama(){
		this.setLaser(true);
		this.noControl = -1;
		this.speed = 40;
	}
	
	// ===========================================================
    // Inner and Anonymous Classes
    // ===========================================================
	
}

